/*-------------------------------------------------------------------------
 *
 * md5_common.c
 *	  用于加密密码的所有MD5实现之间共享的例程。
 *
 * Sverre H. Huseby <sverrehu@online.no>
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *	  src/common/md5_common.c
 *
 *-------------------------------------------------------------------------
 */

#ifndef FRONTEND
#include "postgres.h"
#else
#include "postgres_fe.h"
#endif

#include "common/cryptohash.h"
#include "common/md5.h"

static void fc_bytesToHex(uint8 fc_b[16], char *fc_s)
{
	static const char *fc_hex = "0123456789abcdef";
	int			fc_q,
				fc_w;

	for (fc_q = 0, fc_w = 0; fc_q < 16; fc_q++)
	{
		fc_s[fc_w++] = fc_hex[(fc_b[fc_q] >> 4) & 0x0F];
		fc_s[fc_w++] = fc_hex[fc_b[fc_q] & 0x0F];
	}
	fc_s[fc_w] = '\0';
}

#ifdef FDD
bool bytesToHexs(uint8 *fc_str, int fc_strLen, char *fc_dest, int fc_destlen)
{
	static const char *fc_hex = "0123456789abcdef";
	int			fc_q,
				fc_w;

	if (fc_destlen < (fc_strLen*2 + 1) )
	{
		return false;
	}

	for (fc_q = 0, fc_w = 0; fc_q < fc_strLen; fc_q++)
	{
		fc_dest[fc_w++] = fc_hex[(fc_str[fc_q] >> 4) & 0x0F];
		fc_dest[fc_w++] = fc_hex[fc_str[fc_q] & 0x0F];
	}
	fc_dest[fc_w] = '\0';
	return true;
}

bool HexTobytes(char *fc_str, int fc_strLen, uint8 *fc_dest, int fc_destlen)
{
	unsigned int fc_val = 0;
	if (fc_strLen % 2 != 0 || fc_destlen < fc_strLen/2) 
	{
		return false;
	}
	for(int fc_i = 0; fc_i < fc_strLen; fc_i += 2)
	{
		sscanf(fc_str + fc_i, "%02x", &fc_val);
		fc_dest[fc_i / 2] = fc_val;
	}
	return true;
}

/*
 *	返回的数组是通过malloc分配的。调用者应当在不再需要时释放它。
 */
static uint8 * fc_createPaddedCopyWithLength(const uint8 *fc_b, uint32 *fc_l)
{
	uint8	   *fc_ret;
	uint32		fc_q;
	uint32		fc_len,
				fc_newLen448;
	uint32		fc_len_high,
				fc_len_low;		/* 64位值拆分为32位部分 */

	fc_len = ((fc_b == NULL) ? 0 : *fc_l);
	fc_newLen448 = fc_len + 64 - (fc_len % 64) - 8;
	if (fc_newLen448 <= fc_len)
		fc_newLen448 += 64;

	*fc_l = fc_newLen448 + 8;
	if ((fc_ret = (uint8 *) malloc(sizeof(uint8) * *fc_l)) == NULL)
		return NULL;

	if (fc_b != NULL)
		memcpy(fc_ret, fc_b, sizeof(uint8) * fc_len);

	/* 填充 */
	fc_ret[fc_len] = 0x80;
	for (fc_q = fc_len + 1; fc_q < fc_newLen448; fc_q++)
		fc_ret[fc_q] = 0x00;

	/* 追加长度作为64位比特计数 */
	fc_len_low = fc_len;
	/* 拆分为两个32位值 */
	/* 我们只观察底部32位 */
	fc_len_high = fc_len >> 29;
	fc_len_low <<= 3;
	fc_q = fc_newLen448;
	fc_ret[fc_q++] = (fc_len_low & 0xff);
	fc_len_low >>= 8;
	fc_ret[fc_q++] = (fc_len_low & 0xff);
	fc_len_low >>= 8;
	fc_ret[fc_q++] = (fc_len_low & 0xff);
	fc_len_low >>= 8;
	fc_ret[fc_q++] = (fc_len_low & 0xff);
	fc_ret[fc_q++] = (fc_len_high & 0xff);
	fc_len_high >>= 8;
	fc_ret[fc_q++] = (fc_len_high & 0xff);
	fc_len_high >>= 8;
	fc_ret[fc_q++] = (fc_len_high & 0xff);
	fc_len_high >>= 8;
	fc_ret[fc_q] = (fc_len_high & 0xff);

	return fc_ret;
}

#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
#define ROT_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))

static void fc_doTheRounds(uint32 fc_X[16], uint32 fc_state[4])
{
	uint32		fc_a,
				fc_b,
				fc_c,
				fc_d;

	fc_a = fc_state[0];
	fc_b = fc_state[1];
	fc_c = fc_state[2];
	fc_d = fc_state[3];

	/* 第一轮 */
	fc_a = fc_b + ROT_LEFT((fc_a + F(fc_b, fc_c, fc_d) + fc_X[0] + 0xd76aa478), 7);	/* 1 */
	fc_d = fc_a + ROT_LEFT((fc_d + F(fc_a, fc_b, fc_c) + fc_X[1] + 0xe8c7b756), 12); /* 2 */
	fc_c = fc_d + ROT_LEFT((fc_c + F(fc_d, fc_a, fc_b) + fc_X[2] + 0x242070db), 17); /* 3 */
	fc_b = fc_c + ROT_LEFT((fc_b + F(fc_c, fc_d, fc_a) + fc_X[3] + 0xc1bdceee), 22); /* 4 */
	fc_a = fc_b + ROT_LEFT((fc_a + F(fc_b, fc_c, fc_d) + fc_X[4] + 0xf57c0faf), 7);	/* 5 */
	fc_d = fc_a + ROT_LEFT((fc_d + F(fc_a, fc_b, fc_c) + fc_X[5] + 0x4787c62a), 12); /* 6 */
	fc_c = fc_d + ROT_LEFT((fc_c + F(fc_d, fc_a, fc_b) + fc_X[6] + 0xa8304613), 17); /* 7 */
	fc_b = fc_c + ROT_LEFT((fc_b + F(fc_c, fc_d, fc_a) + fc_X[7] + 0xfd469501), 22); /* 8 */
	fc_a = fc_b + ROT_LEFT((fc_a + F(fc_b, fc_c, fc_d) + fc_X[8] + 0x698098d8), 7);	/* 9 */
	fc_d = fc_a + ROT_LEFT((fc_d + F(fc_a, fc_b, fc_c) + fc_X[9] + 0x8b44f7af), 12); /* 10 */
	fc_c = fc_d + ROT_LEFT((fc_c + F(fc_d, fc_a, fc_b) + fc_X[10] + 0xffff5bb1), 17);	/* 11 */
	fc_b = fc_c + ROT_LEFT((fc_b + F(fc_c, fc_d, fc_a) + fc_X[11] + 0x895cd7be), 22);	/* 12 */
	fc_a = fc_b + ROT_LEFT((fc_a + F(fc_b, fc_c, fc_d) + fc_X[12] + 0x6b901122), 7); /* 13 */
	fc_d = fc_a + ROT_LEFT((fc_d + F(fc_a, fc_b, fc_c) + fc_X[13] + 0xfd987193), 12);	/* 14 */
	fc_c = fc_d + ROT_LEFT((fc_c + F(fc_d, fc_a, fc_b) + fc_X[14] + 0xa679438e), 17);	/* 15 */
	fc_b = fc_c + ROT_LEFT((fc_b + F(fc_c, fc_d, fc_a) + fc_X[15] + 0x49b40821), 22);	/* 16 */

	/* 第二轮 */
	fc_a = fc_b + ROT_LEFT((fc_a + G(fc_b, fc_c, fc_d) + fc_X[1] + 0xf61e2562), 5);	/* 17 */
	fc_d = fc_a + ROT_LEFT((fc_d + G(fc_a, fc_b, fc_c) + fc_X[6] + 0xc040b340), 9);	/* 18 */
	fc_c = fc_d + ROT_LEFT((fc_c + G(fc_d, fc_a, fc_b) + fc_X[11] + 0x265e5a51), 14);	/* 19 */
	fc_b = fc_c + ROT_LEFT((fc_b + G(fc_c, fc_d, fc_a) + fc_X[0] + 0xe9b6c7aa), 20); /* 20 */
	fc_a = fc_b + ROT_LEFT((fc_a + G(fc_b, fc_c, fc_d) + fc_X[5] + 0xd62f105d), 5);	/* 21 */
	fc_d = fc_a + ROT_LEFT((fc_d + G(fc_a, fc_b, fc_c) + fc_X[10] + 0x02441453), 9); /* 22 */
	fc_c = fc_d + ROT_LEFT((fc_c + G(fc_d, fc_a, fc_b) + fc_X[15] + 0xd8a1e681), 14);	/* 23 */
	fc_b = fc_c + ROT_LEFT((fc_b + G(fc_c, fc_d, fc_a) + fc_X[4] + 0xe7d3fbc8), 20); /* 24 */
	fc_a = fc_b + ROT_LEFT((fc_a + G(fc_b, fc_c, fc_d) + fc_X[9] + 0x21e1cde6), 5);	/* 25 */
	fc_d = fc_a + ROT_LEFT((fc_d + G(fc_a, fc_b, fc_c) + fc_X[14] + 0xc33707d6), 9); /* 26 */
	fc_c = fc_d + ROT_LEFT((fc_c + G(fc_d, fc_a, fc_b) + fc_X[3] + 0xf4d50d87), 14); /* 27 */
	fc_b = fc_c + ROT_LEFT((fc_b + G(fc_c, fc_d, fc_a) + fc_X[8] + 0x455a14ed), 20); /* 28 */
	fc_a = fc_b + ROT_LEFT((fc_a + G(fc_b, fc_c, fc_d) + fc_X[13] + 0xa9e3e905), 5); /* 29 */
	fc_d = fc_a + ROT_LEFT((fc_d + G(fc_a, fc_b, fc_c) + fc_X[2] + 0xfcefa3f8), 9);	/* 30 */
	fc_c = fc_d + ROT_LEFT((fc_c + G(fc_d, fc_a, fc_b) + fc_X[7] + 0x676f02d9), 14); /* 31 */
	fc_b = fc_c + ROT_LEFT((fc_b + G(fc_c, fc_d, fc_a) + fc_X[12] + 0x8d2a4c8a), 20);	/* 32 */

	/* 第三轮 */
	fc_a = fc_b + ROT_LEFT((fc_a + H(fc_b, fc_c, fc_d) + fc_X[5] + 0xfffa3942), 4);	/* 33 */
	fc_d = fc_a + ROT_LEFT((fc_d + H(fc_a, fc_b, fc_c) + fc_X[8] + 0x8771f681), 11); /* 34 */
	fc_c = fc_d + ROT_LEFT((fc_c + H(fc_d, fc_a, fc_b) + fc_X[11] + 0x6d9d6122), 16);	/* 35 */
	fc_b = fc_c + ROT_LEFT((fc_b + H(fc_c, fc_d, fc_a) + fc_X[14] + 0xfde5380c), 23);	/* 36 */
	fc_a = fc_b + ROT_LEFT((fc_a + H(fc_b, fc_c, fc_d) + fc_X[1] + 0xa4beea44), 4);	/* 37 */
	fc_d = fc_a + ROT_LEFT((fc_d + H(fc_a, fc_b, fc_c) + fc_X[4] + 0x4bdecfa9), 11); /* 38 */
	fc_c = fc_d + ROT_LEFT((fc_c + H(fc_d, fc_a, fc_b) + fc_X[7] + 0xf6bb4b60), 16); /* 39 */
	fc_b = fc_c + ROT_LEFT((fc_b + H(fc_c, fc_d, fc_a) + fc_X[10] + 0xbebfbc70), 23);	/* 40 */
	fc_a = fc_b + ROT_LEFT((fc_a + H(fc_b, fc_c, fc_d) + fc_X[13] + 0x289b7ec6), 4); /* 41 */
	fc_d = fc_a + ROT_LEFT((fc_d + H(fc_a, fc_b, fc_c) + fc_X[0] + 0xeaa127fa), 11); /* 42 */
	fc_c = fc_d + ROT_LEFT((fc_c + H(fc_d, fc_a, fc_b) + fc_X[3] + 0xd4ef3085), 16); /* 43 */
	fc_b = fc_c + ROT_LEFT((fc_b + H(fc_c, fc_d, fc_a) + fc_X[6] + 0x04881d05), 23); /* 44 */
	fc_a = fc_b + ROT_LEFT((fc_a + H(fc_b, fc_c, fc_d) + fc_X[9] + 0xd9d4d039), 4);	/* 45 */
	fc_d = fc_a + ROT_LEFT((fc_d + H(fc_a, fc_b, fc_c) + fc_X[12] + 0xe6db99e5), 11);	/* 46 */
	fc_c = fc_d + ROT_LEFT((fc_c + H(fc_d, fc_a, fc_b) + fc_X[15] + 0x1fa27cf8), 16);	/* 47 */
	fc_b = fc_c + ROT_LEFT((fc_b + H(fc_c, fc_d, fc_a) + fc_X[2] + 0xc4ac5665), 23); /* 48 */

	/* 第四轮 */
	fc_a = fc_b + ROT_LEFT((fc_a + I(fc_b, fc_c, fc_d) + fc_X[0] + 0xf4292244), 6);	/* 49 */
	fc_d = fc_a + ROT_LEFT((fc_d + I(fc_a, fc_b, fc_c) + fc_X[7] + 0x432aff97), 10); /* 50 */
	fc_c = fc_d + ROT_LEFT((fc_c + I(fc_d, fc_a, fc_b) + fc_X[14] + 0xab9423a7), 15);	/* 51 */
	fc_b = fc_c + ROT_LEFT((fc_b + I(fc_c, fc_d, fc_a) + fc_X[5] + 0xfc93a039), 21); /* 52 */
	fc_a = fc_b + ROT_LEFT((fc_a + I(fc_b, fc_c, fc_d) + fc_X[12] + 0x655b59c3), 6); /* 53 */
	fc_d = fc_a + ROT_LEFT((fc_d + I(fc_a, fc_b, fc_c) + fc_X[3] + 0x8f0ccc92), 10); /* 54 */
	fc_c = fc_d + ROT_LEFT((fc_c + I(fc_d, fc_a, fc_b) + fc_X[10] + 0xffeff47d), 15);	/* 55 */
	fc_b = fc_c + ROT_LEFT((fc_b + I(fc_c, fc_d, fc_a) + fc_X[1] + 0x85845dd1), 21); /* 56 */
	fc_a = fc_b + ROT_LEFT((fc_a + I(fc_b, fc_c, fc_d) + fc_X[8] + 0x6fa87e4f), 6);	/* 57 */
	fc_d = fc_a + ROT_LEFT((fc_d + I(fc_a, fc_b, fc_c) + fc_X[15] + 0xfe2ce6e0), 10);	/* 58 */
	fc_c = fc_d + ROT_LEFT((fc_c + I(fc_d, fc_a, fc_b) + fc_X[6] + 0xa3014314), 15); /* 59 */
	fc_b = fc_c + ROT_LEFT((fc_b + I(fc_c, fc_d, fc_a) + fc_X[13] + 0x4e0811a1), 21);	/* 60 */
	fc_a = fc_b + ROT_LEFT((fc_a + I(fc_b, fc_c, fc_d) + fc_X[4] + 0xf7537e82), 6);	/* 61 */
	fc_d = fc_a + ROT_LEFT((fc_d + I(fc_a, fc_b, fc_c) + fc_X[11] + 0xbd3af235), 10);	/* 62 */
	fc_c = fc_d + ROT_LEFT((fc_c + I(fc_d, fc_a, fc_b) + fc_X[2] + 0x2ad7d2bb), 15); /* 63 */
	fc_b = fc_c + ROT_LEFT((fc_b + I(fc_c, fc_d, fc_a) + fc_X[9] + 0xeb86d391), 21); /* 64 */

	fc_state[0] += fc_a;
	fc_state[1] += fc_b;
	fc_state[2] += fc_c;
	fc_state[3] += fc_d;
}

static int fc_calculateDigestFromBuffer(const uint8 *fc_b, uint32 fc_len, uint8 fc_sum[16])
{
	register uint32 fc_i,
				fc_j,
				fc_k,
				fc_newI;
	uint32		fc_l;
	uint8	   *fc_input;
	register uint32 *fc_wbp;
	uint32		fc_workBuff[16],
				fc_state[4];

	fc_l = fc_len;

	fc_state[0] = 0x67452301;
	fc_state[1] = 0xEFCDAB89;
	fc_state[2] = 0x98BADCFE;
	fc_state[3] = 0x10325476;

	if ((fc_input = fc_createPaddedCopyWithLength(fc_b, &fc_l)) == NULL)
		return 0;

	for (fc_i = 0;;)
	{
		if ((fc_newI = fc_i + 16 * 4) > fc_l)
			break;
		fc_k = fc_i + 3;
		for (fc_j = 0; fc_j < 16; fc_j++)
		{
			fc_wbp = (fc_workBuff + fc_j);
			*fc_wbp = fc_input[fc_k--];
			*fc_wbp <<= 8;
			*fc_wbp |= fc_input[fc_k--];
			*fc_wbp <<= 8;
			*fc_wbp |= fc_input[fc_k--];
			*fc_wbp <<= 8;
			*fc_wbp |= fc_input[fc_k];
			fc_k += 7;
		}
		fc_doTheRounds(fc_workBuff, fc_state);
		fc_i = fc_newI;
	}
	free(fc_input);

	fc_j = 0;
	for (fc_i = 0; fc_i < 4; fc_i++)
	{
		fc_k = fc_state[fc_i];
		fc_sum[fc_j++] = (fc_k & 0xff);
		fc_k >>= 8;
		fc_sum[fc_j++] = (fc_k & 0xff);
		fc_k >>= 8;
		fc_sum[fc_j++] = (fc_k & 0xff);
		fc_k >>= 8;
		fc_sum[fc_j++] = (fc_k & 0xff);
	}
	return 1;
}


bool fdb_md5_hash(const void *fc_buff, size_t fc_len, char *fc_hexsum)
{
	uint8		fc_sum[16];

	if (!fc_calculateDigestFromBuffer(fc_buff, fc_len, fc_sum))
		return false;

	fc_bytesToHex(fc_sum, fc_hexsum);
	return true;
}

bool fdb_md5_binary(const void *fc_buff, size_t fc_len, void *fc_outbuf)
{
	if (!fc_calculateDigestFromBuffer(fc_buff, fc_len, fc_outbuf))
		return false;
	return true;
}


#endif //FDD

/*
 *	pg_md5_hash
 *
 *	计算缓冲区中字节的MD5值。
 *
 *	概要	  #include "md5.h"
 *			  int pg_md5_hash(const void *buff, size_t len, char *hexsum)
 *
 *	输入		  buff	  包含要计算MD5值的字节的缓冲区。
 *				  len	  缓冲区中的字节数。
 *
 *	输出		  hexsum  以'\0'结尾的字符串，表示MD5值的十六进制数字。一个MD5值长度为16字节。
 *				  每个字节由两个十六进制字符表示。因此需要提供一个包含33个字符的数组，包括结尾的'\0'。
 *
 *				  errstr  如果失败返回时，填充常量字符串错误消息；成功时为NULL。
 *
 *	返回		  失败时返回false（内部缓冲区内存不足或MD5计算失败），成功时返回true。
 *
 *	标准	  MD5在RFC 1321中有描述。
 *
 *	作者	  Sverre H. Huseby <sverrehu@online.no>
 *
 */

bool pg_md5_hash(const void *fc_buff, size_t fc_len, char *fc_hexsum, const char **fc_errstr)
{
	uint8		fc_sum[MD5_DIGEST_LENGTH];
	pg_cryptohash_ctx *fc_ctx;

	*fc_errstr = NULL;
	fc_ctx = pg_cryptohash_create(PG_MD5);
	if (fc_ctx == NULL)
	{
		*fc_errstr = pg_cryptohash_error(NULL);	/* 返回 OOM */
		return false;
	}

	if (pg_cryptohash_init(fc_ctx) < 0 ||
		pg_cryptohash_update(fc_ctx, fc_buff, fc_len) < 0 ||
		pg_cryptohash_final(fc_ctx, fc_sum, sizeof(fc_sum)) < 0)
	{
		*fc_errstr = pg_cryptohash_error(fc_ctx);
		pg_cryptohash_free(fc_ctx);
		return false;
	}

	fc_bytesToHex(fc_sum, fc_hexsum);
	pg_cryptohash_free(fc_ctx);
	return true;
}

/*
 * pg_md5_binary
 *
 * 与上述相同，区别在于MD5摘要以二进制字符串的形式返回
 * （大小为MD5_DIGEST_LENGTH），而不是转换为ASCII十六进制。
 */
bool pg_md5_binary(const void *fc_buff, size_t fc_len, void *fc_outbuf, const char **fc_errstr)
{
	pg_cryptohash_ctx *fc_ctx;

	*fc_errstr = NULL;
	fc_ctx = pg_cryptohash_create(PG_MD5);
	if (fc_ctx == NULL)
	{
		*fc_errstr = pg_cryptohash_error(NULL);	/* 返回 OOM */
		return false;
	}

	if (pg_cryptohash_init(fc_ctx) < 0 ||
		pg_cryptohash_update(fc_ctx, fc_buff, fc_len) < 0 ||
		pg_cryptohash_final(fc_ctx, fc_outbuf, MD5_DIGEST_LENGTH) < 0)
	{
		*fc_errstr = pg_cryptohash_error(fc_ctx);
		pg_cryptohash_free(fc_ctx);
		return false;
	}

	pg_cryptohash_free(fc_ctx);
	return true;
}


/*
 * 计算“passwd”（一个以空字符结束的字符串）后
 * 跟着“salt”（不需要以空字符结束）的MD5校验和。
 *
 * 输出格式为“md5”后跟32个十六进制数字的MD5校验和。
 * 因此，输出缓冲区“buf”必须至少为36字节长。
 *
 * 如果一切正常则返回true，如有错误则返回false，*errstr提供一些
 * 错误上下文。
 */
bool pg_md5_encrypt(const char *fc_passwd, const char *fc_salt, size_t fc_salt_len,
			   char *fc_buf, const char **fc_errstr)
{
	size_t		fc_passwd_len = strlen(fc_passwd);

	/* 这里的 +1 只是为了避免不可移植的 malloc(0) 风险 */
	char	   *fc_crypt_buf = malloc(fc_passwd_len + fc_salt_len + 1);
	bool		fc_ret;

	if (!fc_crypt_buf)
	{
		*fc_errstr = _("out of memory");
		return false;
	}

	/*
	 * 将盐放在最后，因为它可能被试图破解
	 * MD5输出的用户所知道。
	 */
	memcpy(fc_crypt_buf, fc_passwd, fc_passwd_len);
	memcpy(fc_crypt_buf + fc_passwd_len, fc_salt, fc_salt_len);

	strcpy(fc_buf, "md5");
	fc_ret = pg_md5_hash(fc_crypt_buf, fc_passwd_len + fc_salt_len, fc_buf + 3, fc_errstr);

	free(fc_crypt_buf);

	return fc_ret;
}
